package com.geek.novel.utils

import android.os.Environment
import android.util.Log
import com.geek.novel.common.Constant
import java.io.*
import java.text.SimpleDateFormat
import java.util.*

/**
 * Created by  on 2017/8/9.
 */
object LogCatUtil {

    /**打印所有日志*/
    private const val printLog = Constant.isPrintLog
    /**打印debug日志*/
    private const val printLogLevel = Constant.printLogLevel
    /**打印debug日志*/
    private const val isSaveLog = Constant.isSaveLog
    /**打印debug日志的级别*/
    private const val saveLogLevel = Constant.saveLogLevel

    private const val dateFormat = "yyyy-MM-dd"
    private val formatter = SimpleDateFormat(dateFormat, Locale.SIMPLIFIED_CHINESE)
    private val dateTimeFormatter = SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.SIMPLIFIED_CHINESE)

    /**
     * 调试日志,带文件名、行数显示
     * @param TAG 用于标识日志消息的源。它通常标识发生日志调用的类或活动。
     * @param msg 日志内容
     */
    fun d(TAG: String, msg: String?) {
        println(Log.DEBUG, TAG, "[$fileLineMethod]$msg")
    }


    /**
     * 错误日志输出,带文件名、行数显示
     * @param TAG 用于标识日志消息的源。它通常标识发生日志调用的类或活动。
     * @param msg 日志内容
     */
    fun e(TAG: String, msg: String?, e: Throwable?=null) {
		println(Log.ERROR, TAG, "[$fileLineMethod]$msg", e)
    }

    /**
     * 信息日志输出,带文件名、行数显示
     * @param TAG 用于标识日志消息的源。它通常标识发生日志调用的类或活动。
     * @param msg 日志内容
     */
    fun i(TAG: String, msg: String) {
		println(Log.INFO, TAG, "[$fileLineMethod]$msg")
    }


    /**
     * 警告日志输出,带文件名、行数显示
     * @param TAG 用于标识日志消息的源。它通常标识发生日志调用的类或活动。
     * @param msg 日志内容
     */
    fun w(TAG: String, msg: String) {
        println(Log.WARN, TAG, "[$fileLineMethod]$msg")
    }
	
	
	private fun println(priority: Int, TAG: String, msg: String, e: Throwable?=null){
		if (printLog && priority >= printLogLevel) {
            if(Log.ERROR == priority){
                Log.e(TAG, msg, e)
            }else{
                Log.println(priority, TAG, msg)
            }
		}
		if (isSaveLog && priority >= saveLogLevel) {
			print(priority, TAG, msg, e)
		}
	}
	

    // 获取文件、行数
    private val fileLineMethod: String
        get() {
            val traceElement = Exception().stackTrace[2]
            val toStringBuffer = StringBuffer("[")
                    .append(traceElement.fileName).append(" | ")
                    .append(traceElement.lineNumber).append(" | ")
                    .append(traceElement.methodName).append("]")
            return toStringBuffer.toString()
        }

    // 获取行数
    val lineMethod: String
        get() {
            val traceElement = Exception().stackTrace[2]
            val toStringBuffer = StringBuffer("[")
                    .append(traceElement.lineNumber).append(" | ")
                    .append(traceElement.methodName).append("]")
            return toStringBuffer.toString()
        }

    // 获取文件名
    fun _FILE_(): String {
        val traceElement = Exception().stackTrace[2]
        return traceElement.fileName
    }

    // 获取方法名
    fun _FUNC_(): String {
        val traceElement = Exception().stackTrace[1]
        return traceElement.methodName
    }

    // 获取行数
    fun _LINE_(): Int {
        val traceElement = Exception().stackTrace[1]
        return traceElement.lineNumber
    }

    // 获取时间
    fun _TIME_(): String {
        val now = Date()
        val sdf = SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS")
        return sdf.format(now)
    }

    /**获取日志文件大小*/
    fun getLogFile(priority: Int): String{
        val path = Constant.LOG_PATH
        val date = formatter.format(Date())
        val level = this.getLogLevel(priority)
        return "$path/$date/log-$level.log"
    }

    /**
     * 输入日志到本地文件
     * 最终存在path目录下的logs目录下,以.log为扩展名的文件,1天一个日志文件
     * @param priority 日志级别
     * @param tag 标识
     * @param msg 输入日志内容
     * @return 返回日志文件名;
     */
    private fun print(priority: Int, tag: String, msg: String?, e: Throwable?): String {
        var filename = ""
        if (isSDAva) {
            //删除历史的日志
            this.deleteHistoryLog()

            //获取日志文件
            val path = this.getLogFile(priority)

            val file = File(path)
            if (!file.exists()) {
                createDipPath(path)
            }
            var out: BufferedWriter? = null
            var printWriter: PrintWriter? = null
            try {
                out = BufferedWriter(OutputStreamWriter(FileOutputStream(file, true)))
                printWriter = PrintWriter(out)
                val datetime = dateTimeFormatter.format(Date())
                printWriter.append("$datetime $tag $msg\r\n")
                //打印错误信息
                if(e != null){
                    e.printStackTrace(printWriter)
                }

                filename = path
            } catch (e: IOException) {
                e.printStackTrace()
            } finally {
                try {
                    out?.close()
                    printWriter?.close()
                } catch (e: IOException) {
                    e.printStackTrace()
                }
            }
        }

        return filename
    }

    /**删除历史日志*/
    private fun deleteHistoryLog(){
        val path = Constant.LOG_PATH
        //只保留最近三天的文件
        val rootFile = File(path)
        if(!rootFile.exists()){
            return
        }
        //获取最近N天的文件
        val latestDaysArray = DateUtil.getLatestDaysArray(3, dateFormat)

        //列出所有文件夹，删掉不等于今天的
        val files = rootFile.listFiles()
        for (file in files) {
            val name = file.name
            val result = latestDaysArray.find { it.equals(name) }
            if(result != null){
                continue
            }
            this.deleteLogDir(rootFile, name)
        }
    }

    /**删除日志文件夹*/
    private fun deleteLogDir(rootFile: File, fileName: String){
        val dir = File(rootFile, fileName)
        if(!dir.exists()){
            return
        }
        val files = dir.listFiles()
        for (file in files) {
            if(file.isFile){
                file.delete()
            }
        }
        dir.delete()
    }

    /**
     * 根据文件路径 递归创建文件
     * @param file 文件路径
     */
    private fun createDipPath(file: String) {
        val parentFile = file.substring(0, file.lastIndexOf("/"))
        val file1 = File(file)
        val parent = File(parentFile)
        if (!file1.exists()) {
            parent.mkdirs()
            try {
                file1.createNewFile()
            } catch (e: IOException) {
                e.printStackTrace()
            }

        }
    }

    /**
     * 获取日志级别
     */
    private fun getLogLevel(priority: Int): String{
        if(Log.ERROR == priority){
            return "error"
        }else if(Log.VERBOSE == priority){
            return "verbose"
        }else if(Log.DEBUG == priority){
            return "debug"
        }else if(Log.WARN == priority){
            return "warn"
        }else if(Log.ASSERT == priority){
            return "assert"
        }
        return "info"
    }

    private val isSDAva: Boolean
        get() = Environment.getExternalStorageState() == Environment.MEDIA_MOUNTED || Environment.getExternalStorageDirectory().exists()


}